#include "JsonPath.h"

#include <cctype>

#include "Common/StringUtil.h"
#include "JsonPathSquareBracket.h"
#include "Log/Log.h"
#include "Poco/RegularExpression.h"

JsonPath::JsonPath(std::string strPath)
{
    m_bInvalid = false;
    if (!Tokenization(strPath))
    {
        zlog.SError("%s: tokenization json path error: %s\n", __PRETTY_FUNCTION__, strPath.c_str());
        return;
    }
    Simplification();
    m_bInvalid = true;
}

JsonPath::JsonPath(const JsonPath& r)
{
    m_vectElement.assign(r.m_vectElement.begin(), r.m_vectElement.end());
    m_bInvalid = r.m_bInvalid && !m_vectElement.empty();
}

JsonPath& JsonPath::operator=(const JsonPath& r)
{
    m_vectElement.assign(r.m_vectElement.begin(), r.m_vectElement.end());
    m_bInvalid = r.m_bInvalid &&!m_vectElement.empty();
    return *this;
}

bool JsonPath::IsValid()
{
    return m_bInvalid;
}

bool JsonPath::Tokenization(std::string strPath)
{
    int iPathSize = strPath.size();
    Poco::RegularExpression re(R"(\[.*?\])");
    Poco::RegularExpression::Match match;
    std::string strTmpKey;
    for (int i = 0; i < iPathSize; i++)
    {
        JsonPathToken element;
        char c = strPath[i];
        switch (c)
        {
        case '$':
            element.m_eType = JsonPathTokenType_Root;
            element.m_strTokenName = "$";
            break;
        case '.':
            if (iPathSize > i + 1 && strPath[i + 1] == '.')
            {
                element.m_eType = JsonPathTokenType_DotDot;
                element.m_strTokenName = "..";
                i++;
                break;
            }
            else
            {
                element.m_eType = JsonPathTokenType_Dot;
                element.m_strTokenName = ".";
                break;
            }
        case '[':
            re.match(strPath, i, match);
            if (match.length > 0)
            {
                element.m_eType = JsonPathTokenType_SquareBracketL;
                element.m_strTokenName = strPath.substr(i, match.length);
                i += (match.length - 1);

                JsonPathSquareBracket* p = new JsonPathSquareBracket(element.m_strTokenName);
                element.m_pUserData = (void*)p;
                if (!p->IsValid())
                {
                    zlog.SError("%s: parse json path error: %s\n", __PRETTY_FUNCTION__, strPath.c_str());
                    return false;
                }
                break;
            }
        default:
            element.m_eType = JsonPathTokenType_Key;
            strTmpKey.push_back(c);
            break;
        }
        if (element.m_eType != JsonPathTokenType_Key)
        {
            CheckTmpKey(strTmpKey);
            m_vectElement.push_back(element);
            strTmpKey.clear();
        }
    }

    CheckTmpKey(strTmpKey);

    if (m_vectElement.empty())
    {
        zlog.SError("parse json path error: empty\n");
        return false;
    }
    if (m_vectElement.front().m_eType != JsonPathTokenType_Root)
    {
        zlog.SError("parse json path error: not start with $ \n");
        return false;
    }
    return true;
}

void JsonPath::CheckTmpKey(std::string strTmpKey)
{
    if (!strTmpKey.empty())
    {
        JsonPathToken element;
        element.m_eType = JsonPathTokenType_Key;
        element.m_strTokenName = strTmpKey;
        m_vectElement.push_back(element);
        strTmpKey.clear();
    }
}

void JsonPath::Simplification()
{
    for (std::vector<JsonPathToken>::iterator it = m_vectElement.begin(); it != m_vectElement.end();)
    {
        if (it->m_eType == JsonPathTokenType_Root || it->m_eType == JsonPathTokenType_Dot)
        {
            it = m_vectElement.erase(it);
        }
        else
        {
            ++it;
        }
    }
}
